package com.mf.controller;

import com.mf.bo.CodeDateScopedBo;
import com.mf.bo.DateScopedBo;
import com.mf.bo.calculateHistory.ProfitGatherBo;
import com.mf.bo.calculateHistory.SumCalculateHistoryBo;
import com.mf.entity.*;
import com.mf.result.Result;
import com.mf.service.*;
import com.mf.service.utils.numericalProcedure.BasicParams;
import com.mf.service.utils.numericalProcedure.CalculateProcedure.CalculateProcedure;
import com.mf.service.utils.numericalProcedure.CalculateProcedure.CalculateProcedure1;
import com.mf.utils.DateUtil;
import com.mf.utils.StockGatherUtils;
import com.mf.vo.StockGatherVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;


/**
 * <p>
 * 股票推荐表 前端控制器
 * </p>
 *
 * @author mf
 * @since 2024-06-02
 */
@RestController
@RequestMapping("/codeHistory")
@Slf4j
public class CodeHistoryController {

    @Resource
    private ICodeHistoryService codeHistoryService;

    @Resource
    private ICodeService codeService;

    @Resource
    private ICanPurchaseDmService canPurchaseDmService;

    @Resource
    private ICalculationSummaryService calculationSummaryService;

    @Resource
    private IWinRateService winRateService;
    /**
     * 更新最新历史数据
     */
    @GetMapping("/updateCode")
    public Result<Void> updateCode()
    {
        System.out.println("进入");
        final List<Code> codeList = codeService.findAll();
        // 获取所有股票代码
        for (Code code : codeList) {
            System.out.println(code.getDm());
            codeHistoryService.setNewHistory(code.getDm());
        }
        System.out.println("完成");
        return Result.success();
    }

    /**
     * 根据MA5 MA10 指标计算
     */
    @PostMapping("/calculateMa10")
    public Result<BigDecimal> calculateMa10(
            @Valid @RequestBody DateScopedBo dateScopedBo,
            @RequestParam("dm") String dm) {
        List<Code> codeList;
        if (dm == null || dm.isEmpty()) {
            codeList = codeService.findAll();
        } else {
            codeList = codeService.findAll(dm);
        }
        final CodeDateScopedBo dateScopedBo1 = new CodeDateScopedBo();
        dateScopedBo1.setStartDate(dateScopedBo.getStartDate());
        dateScopedBo1.setEndDate(dateScopedBo.getEndDate());
        winRateService.remove(null);
        List<String> code222 = new ArrayList<>();
        for (Code code : codeList) {
            dateScopedBo1.setDm(code.getDm());
//            dateScopedBo1.setDm(dm);
            // 日线
            final List<CodeHistory> codeHistories = codeHistoryService.getCodeHistoriesByCodeDateScoped(dateScopedBo1);
            if (codeHistories.isEmpty() || codeHistories.get(0).getC().compareTo(new BigDecimal("3.2")) < 0) {
                continue;
            }
            final StockGatherVo stockGather = StockGatherUtils.getStockGather(codeHistories);
            if (stockGather.getKdj() == null || stockGather.getCci() == null) {
                continue;
            }

            int length = stockGather.getMa10().size() - 1;
            boolean ccc = stockGather.getMa10().get(length) > stockGather.getMa10().get(length - 1);
            StockGatherUtils.deleteBeforeDate(stockGather, dateScopedBo.getStartDate());

            final Double v = stockGather.getMa5().get(0);
            // 当天收盘价
            final BigDecimal c = codeHistories.get(codeHistories.size() - 1).getC();
            // 昨天收盘价
            final BigDecimal c2 = codeHistories.get(codeHistories.size() - 2).getC();
            // m5 > m10 + 0.02
            boolean a1 = stockGather.getMa5().get(0) > stockGather.getMa10().get(0) + 0.02;
            // M10 + 前一天的M10

            if (a1 && c.compareTo(c2) > 0 && ccc) {
                System.out.println(stockGather.getDm());
                code222.add(stockGather.getDm());
            }

        }
        log.info("code222:{}", code222);
        return Result.success();
    }


    /**
     * 根据MA5 MA10 指标计算
     */
    @PostMapping("/calculateMa")
    public Result<BigDecimal> calculateMa(
            @Valid @RequestBody DateScopedBo dateScopedBo,
            @RequestParam("dm") String dm,
            @RequestParam("type") String type) {
        List<Code> codeList;
        if (dm == null || dm.isEmpty()) {
            codeList = codeService.findAll();
        } else {
            codeList = codeService.findAll(dm);
        }
        final CodeDateScopedBo dateScopedBo1 = new CodeDateScopedBo();
        dateScopedBo1.setStartDate(dateScopedBo.getStartDate());
        dateScopedBo1.setEndDate(dateScopedBo.getEndDate());
        winRateService.remove(null);

//        for (Code code : codeList) {
//            dateScopedBo1.setDm(code.getDm());
        dateScopedBo1.setDm(dm);
        // 买入价格
        BigDecimal buyPrice = new BigDecimal("0");
        // 卖出价格
        BigDecimal sellPrice = new BigDecimal("0");

        // 盈利数
        int profitNum = 0;
        //失败数
        int failNum = 0;

        // 本金
        BigDecimal capital = new BigDecimal("10000");

        // 日线
        final List<CodeHistory> codeHistories = codeHistoryService.getCodeHistoriesByCodeDateScoped(dateScopedBo1);
//            if (codeHistories.isEmpty()) {
//                continue;
//            }
        final StockGatherVo stockGather = StockGatherUtils.getStockGather(codeHistories);
//            if (stockGather.getKdj() == null) {
//                continue;
//            }

        StockGatherUtils.deleteBeforeDate(stockGather, dateScopedBo.getStartDate());
//            if (stockGather.getDate().length < 5) {
//                continue;
//            }
        for (int i = 15; i < stockGather.getDate().length - 10; i++) {
            // 查询是否MA5是否大于MA110
            boolean ma1 = stockGather.getMa5().get(i) > stockGather.getMa10().get(i) + 0.02;

            // ma10 必须 大于前一日ma10 0.2   必须形成一个向上的趋势
            boolean ma2 = stockGather.getMa10().get(i) >= (stockGather.getMa10().get(i - 1) + 0.01);
            boolean ma3 = isBuy(stockGather, i);

            // kdj中 j线是否大于k线
            boolean kdj1 = stockGather.getKdj().get(i).getJ() > stockGather.getKdj().get(i).getK();
            // 查询 j线是否大于前一日j线
            boolean kdj2 = stockGather.getKdj().get(i).getJ() > stockGather.getKdj().get(i - 1).getJ() + 3;
            // 查询前5日的价格不能超过10%
            final String date = stockGather.getDate()[i];

            BigDecimal earnings = new BigDecimal("0");
            if (ma1 && ma2 && ma3 && kdj1 && kdj2) {
                System.out.println("======================" + date);
                System.out.println("开盘价" + stockGather.getK()[i][0]);
                System.out.println("收盘价" + stockGather.getK()[i][1]);
                // 当天的收盘价格要小于开盘价格往后面去查询直到是是收盘价大于开盘价格
                boolean k1 = stockGather.getK()[i][1] < stockGather.getK()[i][0];
                if (k1) {
                    final int index = findIndex(stockGather, i);
                    if (index != -1) {
                        // 买入价格
                        buyPrice = BigDecimal.valueOf(stockGather.getK()[index][0]);
                        System.out.println(stockGather.getDate()[index] + "入选日期  阴线位置进入" + stockGather.getDm());
                        final int sellIndex = findSellIndex(stockGather, index);

                        if (sellIndex != -1) {
                            i = sellIndex;
                            // 卖出价格
                            sellPrice = BigDecimal.valueOf(stockGather.getK()[i][1]);
                            // 计算收益
                            earnings = sellPrice.subtract(buyPrice).divide(buyPrice, 4, RoundingMode.HALF_UP);
                            capital = capital.setScale(2, RoundingMode.HALF_UP);
                            System.out.println(earnings + "卖出日期" + stockGather.getDate()[i]);
                            System.out.println("买入价格:" + buyPrice + "卖出价格:" + sellPrice + "收益率：" + earnings);
                        }
                    }
                } else {

                    if (i + 1 >= stockGather.getDate().length) {
                        continue;
                    }
                    System.out.println(stockGather.getDate()[i + 1] + "end入选日期  " + stockGather.getDm());

                    // 买入价格
                    buyPrice = BigDecimal.valueOf(stockGather.getK()[i + 1][0]);
//

                    final int sellIndex = findSellIndex(stockGather, i);
                    if (sellIndex != -1) {
                        i = sellIndex;
                        // 卖出价格
                        sellPrice = BigDecimal.valueOf(stockGather.getK()[i][1]);
                        // 计算收益
                        earnings = sellPrice.subtract(buyPrice).divide(buyPrice, 2, RoundingMode.HALF_UP);
                        capital = capital.setScale(2, RoundingMode.HALF_UP);
                        System.out.println(earnings + "卖出日期" + stockGather.getDate()[i]);
                        System.out.println("买入价格:" + buyPrice + "卖出价格:" + sellPrice + "收益率：" + earnings);
                    }
                }

                if (!earnings.equals(new BigDecimal("0"))) {
                    if (earnings.compareTo(BigDecimal.ZERO) > 0) {
                        capital = capital.multiply(earnings).add(capital);
                        profitNum++;
                        System.out.println("======盈利======+++++++++++++++++++++" + capital);

                    } else {
                        BigDecimal ab = capital.multiply(earnings);
                        System.out.println(ab + "=================" + capital);
                        capital = capital.add(ab);
                        failNum++;
                        System.out.println("======失败======+++++++++++++++++++++" + capital);
                    }
                } else {
                    System.out.println("暂无数据");
                }

            }

        }
        final WinRate winRate = new WinRate();
//            winRate.setDm(code.getDm());
//            winRate.setProfitNum(profitNum);
//            winRate.setFailNum(failNum);
//            winRate.setCaptal(capital);
//            winRate.setType(type);
//            winRateService.save(winRate);

        System.out.println(profitNum + "============盈利");
        System.out.println(failNum + "============失败");
//        }
        return Result.success();
    }

    /**
     * 判断是否符合条件
     */
    private boolean isBuy(StockGatherVo stockGather, int i) {

        // 往前查的日期天数
        int days = 4;
        // 价格
        final double v = stockGather.getK()[i][1];
        for (int j = i; j > i - days; j--) {
            // 如果ma10小于前一日ma10
            if (stockGather.getMa10().get(j) < stockGather.getMa10().get(j - 1)) {
                return false;
            }
        }

        for (int j = i; j > i - 15; j--) {
            if (stockGather.getK()[j][1] * 1.08 < v) {
                return false;
            }
        }
        return true;
    }


    /**
     * 计算卖出日期
     */
    private int findSellIndex(StockGatherVo stockGather, int buyIndex) {
        for (int i = buyIndex + 1; i < stockGather.getDate().length; i++) {
            // 如果ma10小于前一日ma10
            if (stockGather.getMa10().get(i) < stockGather.getMa10().get(i - 1)) {
                return i;
            }

        }
        return -1;
    }

    /**
     * 如果当天阴线那么往后推找一天直到是阳线返回对应的下标
     */
    private int findIndex(StockGatherVo stockGather, int index) {

        for (int i = index; i < stockGather.getDate().length; i++) {
            // 查询是否阴线
            boolean k1 = stockGather.getK()[i][1] > stockGather.getK()[i][0];
            // 查询是否MA5是否大于MA110想·
            boolean ma1 = stockGather.getMa5().get(i) < stockGather.getMa10().get(i);
            // kdj中 j线是否大于k线
            boolean kdj1 = stockGather.getKdj().get(i).getJ() > stockGather.getKdj().get(i).getK();
            // 查询 j线是否大于前一日j线
            boolean kdj2 = stockGather.getKdj().get(i).getJ() > stockGather.getKdj().get(i - 1).getJ();
            if (ma1) {
                return -1;
            }
            if (k1 && kdj1 && kdj2) {
                if (i == stockGather.getDate().length - 1) {
                    return -1;
                }
                return i + 1;
            }
        }
        return -1;
    }

    /**
     * 批量保存
     */
    @PostMapping("/saveBatchAll")
    public Result<Void> saveBatchAll(@Valid @RequestBody DateScopedBo dateScopedBo, @RequestParam("dm") String dm) {
        List<Code> codeList;
        System.out.println(dm);
        if (dm == null || dm.isEmpty()) {
            codeList = codeService.findAll();
        } else {
            codeList = codeService.findAll(dm);
        }
        System.out.println(dm);
        codeHistoryService.saveBatchAll(dateScopedBo, codeList);
        return Result.success();
    }

    /**
     * 单条数据新增
     */
    @GetMapping("/setNewHistory")
    public Result<String> setNewHistory(@RequestParam("dm") String dm)
    {
        codeHistoryService.setNewHistory(dm);
        return Result.success();
    }

    /**
     * 删除指定日期范围内的所有数据
     */
    @PostMapping("/deleteAllDateScope")
    public Result<Void> deleteAllDateScope(@RequestBody CodeDateScopedBo codeDateScopedBo) {
        codeHistoryService.deleteAllDateScope(codeDateScopedBo);
        return Result.success();
    }

    /**
     * 获取所有股票历史数据总条数
     */
    @GetMapping("/findAll")
    public Result<List<CodeHistory>> findAll() {
        final List<CodeHistory> list = codeHistoryService.list();
        return Result.success(list);
    }

    /**
     * 获取所有股票历史数据总条数
     */
    @GetMapping("/findAllCount")
    public Result<Long> findAllCount() {
        return Result.success(codeHistoryService.count());
    }

    /**
     * 获取所有股票历史计算指标
     */
    @PostMapping("/findAllStockGather")
    public Result<StockGatherVo> findAllStockGather(@Valid @RequestBody CodeDateScopedBo codeDateScopedBo) {
        StockGatherVo stockGather = StockGatherUtils.getStockGather(codeHistoryService.dateScopedList(codeDateScopedBo));
        return Result.success(stockGather);
    }

    /**
     * 计算指定日期可买入的数据 (获取新数据)
     */
    @GetMapping("calculateHistoryByDate")
    public Result<List<String>> calculateHistoryByDate(@RequestParam("date") String date) {
        final LocalDate localDate = DateUtil.stringToDate(date).minusMonths(3);
        final CodeDateScopedBo codeDateScopedBo = new CodeDateScopedBo();
        codeDateScopedBo.setStartDate(localDate.toString());
        codeDateScopedBo.setEndDate(date);
        List<String> code = codeHistoryService.calculateHistoryByDate(codeDateScopedBo);
        List<CanPurchaseDm> canPurchaseDmList = canPurchaseDmService.getSaveBatchCodeList(code);
        System.out.println("查询完成");
        canPurchaseDmService.saveBatch(canPurchaseDmList);
        return Result.success(code);
    }

    /**
     * 获取时间范围内可购买的数据集合 (历史数据)
     */
    @PostMapping("/findScopedDateCode")
    public Result<SumCalculateHistoryBo> findScopedDateCode(@RequestBody DateScopedBo dateScopedBo) {
        CalculateProcedure procedure1 = new CalculateProcedure1();
        return Result.success(codeHistoryService.findAllDate(dateScopedBo, procedure1));
    }

    /**
     * 批量计算
     */
    @PostMapping("/batchFindScopedDateCode")
    public Result<Void> batchFindScopedDateCode(@RequestBody DateScopedBo dateScopedBo) {
        CalculateProcedure procedure1 = new CalculateProcedure1();
        System.out.println(dateScopedBo.toString());
        for (int i = 0; i <= 10; i++) {
            BasicParams.kdjMin = i;
            for (int j = 30; j <= 80; j++) {
                BasicParams.kdjMax = j;
                System.out.println(i + "=========================" + j);
                final SumCalculateHistoryBo list = codeHistoryService.findAllDate(dateScopedBo, procedure1);
                System.out.println("开始计算");
                getCalculationSummaryVo(list);
            }
        }
        return Result.success();
    }

    public void getCalculationSummaryVo(SumCalculateHistoryBo sumCalculateHistoryBo) {
        System.out.println(sumCalculateHistoryBo.getProfitGatherBoList().size() + "添加数量");
        for (ProfitGatherBo yearBo : sumCalculateHistoryBo.getProfitGatherBoList()) {
            final CalculationSummary calculationSummary = new CalculationSummary();
            calculationSummary.setYear(yearBo.getDate());
            calculationSummary.setMonthTotal(yearBo.getProfitCounts() + yearBo.getFailCounts());
            calculationSummary.setMonthProfitableCount(yearBo.getProfitCounts());
            calculationSummary.setMonthFailCount(yearBo.getFailCounts());
            for (ProfitGatherBo monthBo : yearBo.getProfitGatherBosList()) {
                calculationSummary.setDayProfitableCount(monthBo.getProfitCounts() + calculationSummary.getDayProfitableCount());
                calculationSummary.setDayFailCount(monthBo.getFailCounts() + calculationSummary.getDayFailCount());
                calculationSummary.setDayTotal(monthBo.getProfitCounts() + monthBo.getFailCounts() + calculationSummary.getDayTotal());
            }
            calculationSummary.setKdjMax(BasicParams.kdjMax);
            calculationSummary.setKdjMin(BasicParams.kdjMin);
            System.out.println(BasicParams.kdjMax + "================添加加1=====================" + BasicParams.kdjMin);
            calculationSummaryService.save(calculationSummary);
        }

    }


}
